package com.xujiang.common_core.util.tool;

import android.app.Activity;
import android.app.DownloadManager;
import android.content.Context;
import android.net.Uri;
import android.text.TextUtils;

import com.xujiang.common_core.util.mcallback.Callback;
import com.xujiang.common_core.util.mcallback.Callback2;
import com.xujiang.common_core.util.ourexception.SystemException;

import java.io.File;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;

import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;

/**
 * <a href="http://jodd.org" target="_blank">jodd</a>
 *
 * @author xujiang
 * @version 2017-07-01 18:15
 */
public class Utils {
    /**
     * http://blog.csdn.net/jdsjlzx/article/details/6622408
     *
     * 复杂版 http://android.blog.51cto.com/268543/302529/
     */
    public static final String ANDROID_RESOURCE = "android.resource://";

    /**
     * Resource to Uri
     *
     * @return {@link Uri}
     */
    public static String resourceIdToUri(Context context, int resourceId) {
        return ANDROID_RESOURCE + context.getPackageName() + File.separator + resourceId;  //File.separator为\
    }

    /**
     * 是否为网络地址
     *
     * @return https://zhidao.baidu.com/question/471506646.html
     *
     * http://blog.csdn.net/harvic880925/article/details/44679239
     */
    public static boolean isHtmlUrl(String url) {
        return isHtmlUrl(Uri.parse(url));
    }

    /**
     * 是否为网络地址
     *
     * @return URL与URI很像，两者的格式几乎差不多，但是我们接触的还是URL比较多，就以URL为例说明
     * URL提供了一种访问定位因特网上任意资源的手段，但是这些资源可以通过不同的方法（例如HTTP、FTP、SMTP）来访问，不管怎样，他都基本上由9个部分构成：
     * <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<fragment>
     * scheme：获取资源使用的协议，例如http、ftp等，没有默认值
     * user:password：用户名与密码，这个是一个特殊的存在，一般访问ftp时会用到，他显示的表明了访问资源的用户名与密码。但是这个可以不写，不写的话可能会让你输入用户名密码
     * host：主机，访问那台主机，有时候可以是IP，有时候是主机名，例如www.baidu.com
     * port：端口，访问主机时的端口，如果http访问默认80，可以省略。
     * path：通过host:port我们能找到主机，但是主机上文件很多，通过path则可以定位具体文件。例如www.baidu.com/file/index.html。则path是/file/index.html，表示我们访问/file/index.html这个文件，他很像linux上的路径。
     * params：这个很少见，主要作用就是像服务器提供额外的参数，用来表示本次请求的一些特性。例如ftp传输模式有两种，二进制和文本，你肯定不希望使用文本形式传输二进制图片，这样你的图片下载下来后可能没法看了。为了向应用程序提供更丰富的信息，URL中有个专门的部分来表示这种参数。例如ftp://file.qiandu.com/pub/guid.pdf;type=d其中的type=d就是params
     * query：通过get方式请求的参数，例如：www.qiandu.com/index.html?username=dgh&passwd=123
     * fragment：例如www.qiandu.com/index.html#1。当html页面比较长时，我们通常会将其分为好几段，#1就可以 快速定位到某一段。
     *
     * http://blog.csdn.net/readiay/article/details/52862379
     */
    public static boolean isHtmlUrl(Uri uri) {
        return !TextUtils.isEmpty(uri.getScheme());  //  uri.getScheme() Gets the scheme of this URI. Example: "http"
    }

    /**
     * URL是否为指定网站
     *
     * @return http://blog.csdn.net/chaolin1994/article/details/51470025
     */
    public static boolean isCurAuthority(String baseAuthority, String url) {
        Uri uri = Uri.parse(url);
        if (!isHtmlUrl(uri)) {
            return false;
        }
        String authority = uri.getAuthority();
        if (TextUtils.isEmpty(authority)) {
            return false;
        }
        if (!baseAuthority.contentEquals(authority)) {
            return false;
        }
        return true;
    }

    /**
     * URL链接添加参数
     */
    public static String appendUrlParameter(String url, String key, String value) {
        if (!isHtmlUrl(url)) {
            return url;
        }
        Uri uri = Uri.parse(url);
        if (uri.getBooleanQueryParameter(key, false)) {//有KEY值不修改，查询key是否存在
            return url;
        }
        return new Uri.Builder().scheme(uri.getScheme()).encodedAuthority(uri.getEncodedAuthority())
                .encodedPath(uri.getEncodedPath()).encodedQuery(uri.getEncodedQuery())
                .appendQueryParameter(key, value).encodedFragment(uri.getEncodedFragment()).build()
                .toString();
    }

    private static long exitTime = 0;

    /**
     *双击退出activity
     * @param activity
     */
    public static void doubleExitActivity(final Activity activity) {
        doubleOperation(activity, 2000, "再按一次退出程序！", new Callback.EmptyCallback<Void>() {
            @Override public void onSuccess(Void o) {
                activity.finish();
            }
        });
    }

    /**
     * 双击事件触发
     * @param context {@link Context}
     * @param interval 间隔时间 ms
     * @param msg 提示
     * @param callback 回调{@link Callback#onSuccess(Object)}
     */
    public static void doubleOperation(Context context, int interval, String msg,
            Callback<Void> callback) {
        if ((System.currentTimeMillis() - exitTime) > interval) {  //System.currentTimeMillis() 以毫秒为单位返回当前时间
            exitTime = System.currentTimeMillis();
            //UIUtils.showToast(context, msg, Toast.LENGTH_SHORT);
        } else {
            callback.onSuccess(null);
        }
    }

    /**
     * 这是rx相关的工具
     */
    //---------------------------------------------------------------------------

    /**
     * 当调用Observable.subscribe()，会返回一个Subscription对象。这个对象代表了被观察者和订阅者之间的联系
     * @param subscription
     */
    public static void unsubscribe(Subscription subscription) {
        if (subscription == null) {
            return;
        }
        if (subscription.isUnsubscribed()) {
            return;
        }
        subscription.unsubscribe();  //解注册
    }

    public static <T> Subscriber<T> getSubscribe(final Callback<T> listener) {
        return new Subscriber<T>() {
            @Override public void onStart() {
                super.onStart();
                if (listener != null) {
                    HandlerUtils.runOnUiThread(new Runnable() {
                        @Override public void run() {
                            listener.onPreExecute();  //开始
                        }
                    });
                }
            }

            @Override public void onCompleted() {
                if (listener != null) {
                    listener.onFinish();  //完成
                }
            }

            @Override public void onError(Throwable e) {
                if (listener != null) {
                    listener.onPostExecute();
                    listener.onError(new SystemException(e));
                }
            }

            @Override public void onNext(T t) {
                if (listener != null) {
                    listener.onPostExecute();
                    listener.onSuccess(t);
                }
            }
        };
    }

    public static <T> Subscriber<T> getSubscribe2(final Callback2<T> listener) {
        return new Subscriber<T>() {
            @Override public void onStart() {
                super.onStart();
                if (listener != null) {
                    HandlerUtils.runOnUiThread(new Runnable() {
                        @Override public void run() {
                            listener.onPreExecute();
                        }
                    });
                }
            }

            @Override public void onCompleted() {
                if (listener != null) {
                    listener.onFinish();
                }
            }

            @Override public void onError(Throwable e) {
                if (listener != null) {
                    listener.onPostExecute();
                    listener.onError(e);
                }
            }

            @Override public void onNext(T t) {
                if (listener != null) {
                    listener.onPostExecute();
                    listener.onSuccess(t);
                }
            }
        };
    }

    public static <T> Subscription addSubscribe(Observable<T> observable,
            final Callback<T> listener) {
        return observable.observeOn(AndroidSchedulers.mainThread())
                .subscribe(getSubscribe(listener));
    }




    // rx结束 ---------------------------------------------------------------- misc

    public static String getContentDispositionFileName(String contentDisposition, String def) {
        if (TextUtils.isEmpty(contentDisposition)) {
            return def;
        }
        String[] f = TextUtils.split(contentDisposition, "=");  //按等号分成数组
        String fileName;
        if (f.length < 2) {
            return def;
        } else {
            fileName = f[1];
            return fileName.replaceAll("\"", "");  //把 " 去掉  即替换成null
        }
    }

    /**
     * download file to sd /
     * setDestinationInExternalPublicDir
     * @param context
     * @param title
     * @param url
     * @param dir
     * @param fileName
     * @return
     */
    public static long systemDownloadPublicDir(Context context, String title, String url,
            String dir, String fileName) {
        Uri downUrl = Uri.parse(url);
        DownloadManager downloadManager = (DownloadManager) context
                .getSystemService(Context.DOWNLOAD_SERVICE);
        DownloadManager.Request request = getSystemDownloadRequest(title, downUrl,
                DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
                .setDestinationInExternalPublicDir(dir, fileName);
        return downloadManager.enqueue(request);
    }

    /**
     * download file to sd /Android/data/:package/files/
     * setDestinationInExternalFilesDir
     * @param context
     * @param title
     * @param url
     * @param dir
     * @param fileName
     * @return
     */
    public static long systemDownloadFilesDir(Context context, String title, String url, String dir,
            String fileName) {
        Uri downUrl = Uri.parse(url);
        DownloadManager downloadManager = (DownloadManager) context
                .getSystemService(Context.DOWNLOAD_SERVICE);
        DownloadManager.Request request = getSystemDownloadRequest(title, downUrl,
                DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
                .setDestinationInExternalFilesDir(context, dir, fileName);
        return downloadManager.enqueue(request);
    }



    public static DownloadManager.Request getSystemDownloadRequest(String title, Uri downloadUrl,
            int notificationVisibility) {
        DownloadManager.Request request = new DownloadManager.Request(downloadUrl);
        request.setAllowedNetworkTypes(
                DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
        // 设置标题
        request.setTitle(title);
        // 显示下载进度的提示
        request.setNotificationVisibility(notificationVisibility);
        request.setVisibleInDownloadsUi(true);
        return request;
    }


    /**
     * Safely compares two objects just like <code>equals()</code> would, except
     * it allows any of the 2 objects to be <code>null</code>.
     *
     * @return <code>true</code> if arguments are equal, otherwise <code>false</code>
     */
    public static boolean equals(Object obj1, Object obj2) {
        return (obj1 != null) ? (obj1.equals(obj2)) : (obj2 == null);
    }

    /**
     * Returns string representation of an object, while checking for <code>null</code>.
     */
    public static String toString(Object value) {
        if (value == null) {
            return null;
        }
        return value.toString();
    }

    /**
     * Returns length of the object. Returns <code>0</code> for <code>null</code>.
     * Returns <code>-1</code> for objects without a length.
     */
    public static int length(Object obj) {
        if (obj == null) {
            return 0;
        }
        if (obj instanceof CharSequence) {
            return ((CharSequence) obj).length();
        }
        if (obj instanceof Collection) {
            return ((Collection) obj).size();
        }
        if (obj instanceof Map) {
            return ((Map) obj).size();
        }

        int count;
        if (obj instanceof Iterator) {
            Iterator iter = (Iterator) obj;
            count = 0;
            while (iter.hasNext()) {
                count++;
                iter.next();
            }
            return count;
        }
        if (obj instanceof Enumeration) {
            Enumeration enumeration = (Enumeration) obj;
            count = 0;
            while (enumeration.hasMoreElements()) {
                count++;
                enumeration.nextElement();
            }
            return count;
        }
        if (obj.getClass().isArray()) {
            return Array.getLength(obj);
        }
        return -1;
    }

    /**
     * Returns <code>true</code> if first argument contains provided element.
     * It works for strings, collections, maps and arrays.
     s	 */
    public static boolean containsElement(Object obj, Object element) {
        if (obj == null) {
            return false;
        }
        if (obj instanceof String) {
            if (element == null) {
                return false;
            }
            return ((String) obj).contains(element.toString());
        }
        if (obj instanceof Collection) {
            return ((Collection) obj).contains(element);
        }
        if (obj instanceof Map) {
            return ((Map) obj).values().contains(element);
        }

        if (obj instanceof Iterator) {
            Iterator iter = (Iterator) obj;
            while (iter.hasNext()) {
                Object o = iter.next();
                if (equals(o, element)) {
                    return true;
                }
            }
            return false;
        }
        if (obj instanceof Enumeration) {
            Enumeration enumeration = (Enumeration) obj;
            while (enumeration.hasMoreElements()) {
                Object o = enumeration.nextElement();
                if (equals(o, element)) {
                    return true;
                }
            }
            return false;
        }
        if (obj.getClass().isArray()) {
            int len = Array.getLength(obj);
            for (int i = 0; i < len; i++) {
                Object o = Array.get(obj, i);
                if (equals(o, element)) {
                    return true;
                }
            }
        }
        return false;
    }

}
